package com.tender.deferredresult;

import com.alibaba.nacos.shaded.com.google.common.util.concurrent.RateLimiter;
import com.tender.common.Result;
import com.tender.enums.ErrorTypeEnum;
import com.tender.properties.CommonProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.async.DeferredResult;

@Slf4j
@Service
public class ApiCallWithDeferredResultStrategy implements DeferredResultBizProcessingStrategy<Result<Object>>, InitializingBean {
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Override
    public void afterPropertiesSet() throws Exception {
        rateLimiter = RateLimiter.create(commonProperties.getRateLimit());
    }

    @Autowired
    private CommonProperties commonProperties;
    // 限流工具
    private RateLimiter rateLimiter = null;

    @Override
    public void process(DeferredResult<Result<Object>> deferredResult, Runnable runnable) {
        boolean flag = rateLimiter.tryAcquire();
        if (flag) {
            // 超时返回结果
            log.error("【系统调用超时】");
            deferredResult.onTimeout(() -> {
                deferredResult.setErrorResult(Result.fail(ErrorTypeEnum.SYSTEM_INVOKE_TIME_OUT_ERROR.getCode(),
                        ErrorTypeEnum.SYSTEM_INVOKE_TIME_OUT_ERROR.getErrorMsgCn()));
            });

            // 异常响应
            deferredResult.onError(throwable -> {
                log.error("【系统调用异常】具体异常：", throwable);
                deferredResult.setErrorResult(Result.fail(ErrorTypeEnum.SYSTEM_INVOKE_WITH_ERROR.getCode(),
                        ErrorTypeEnum.SYSTEM_INVOKE_WITH_ERROR.getErrorMsgCn()));
            });

            // runnable 中【异步】处理具体的业务
            threadPoolTaskExecutor.execute(runnable);
        } else {
            log.info("【系统调用被限流】");
            deferredResult.setErrorResult(Result.fail(ErrorTypeEnum.SYSTEM_INVOKE_RATE_LIMITER_ERROR.getCode(),
                    ErrorTypeEnum.SYSTEM_INVOKE_RATE_LIMITER_ERROR.getErrorMsgCn()));
        }
    }

}
